package models;

import java.util.Enumeration;
import java.util.Random;
import java.util.Vector;

public class HangMan1 {

	/**
	 * The currentWord must only contain letters from the specified alphabet
	 */
	public String currentWord;

	/**
	 * This must be initialised to 0 and should be incremented every time an
	 * error is made; up to the maximum number of errors allowed
	 */
	public int errorCount;

	/**
	 * lettersFound is an array for storing which of the letters of the current
	 * word have been found by the players correct guesses.<br>
	 * For example, if 't' has been guessed in the word "test" then the
	 * lettersFound array will be [true, false, false, true]
	 */
	public boolean[] lettersFound;

	public boolean won;

	public boolean lost;

	/**
	 * The maximum number of errors that a player can make before the game is
	 * over<br>
	 */
	public final int ERROR_MAX = 10;

	/**
	 * The first alphabet character allowed in the word to be guessed
	 */
	public final char ALPHABET_FROM = 'a';

	/**
	 * The last alphabet character allowed in the word to be guessed
	 */
	public final char ALPHABET_TO = 'z';

	/**
	 * The size of the word alphabet
	 */
	public final int ALPHABET_SIZE = 'z' - 'a' + 1;

	/**
	 * lettersTried is an array for storing which of the letters of the alphabet
	 * have been guessed by the player since the beginning of the game.<br>
	 * For example, if the player has tried letters 'a' 'c' and 'z' this array
	 * will have the value [true, false, true, false, ..., false, true]
	 */
	public boolean[] lettersTried = new boolean[ALPHABET_SIZE];

	// public abstract void tryLetter(char letter) throws IllegalStateException,
	// IllegalArgumentException;

	/**
	 * True if:
	 * <ul>
	 * <li>the first and last letters of the word alphabet are in correct
	 * alphabetic order,</li>
	 * <li>the alphabet has at least 2 letters,</li>
	 * <li>it is possible to have a losing game because the alphabet is bigger
	 * than the allowed number of errors</li>
	 * <li>the number of errors allowed is non-negative</li>
	 * </ul>
	 * otherwise false
	 */
	boolean INVARIANT_OF_CLASS = (ALPHABET_FROM < ALPHABET_TO
			&& ALPHABET_SIZE > ERROR_MAX && ERROR_MAX >= 0);

	/**
	 * The words in the word store (with no repeated elements); and may be empty
	 * All words are written in lower case and letters restricted to lower case
	 * 'a'..'z'
	 */
	public Vector<String> allWords;

	/**
	 * The rng responsible for picking a word randomly
	 */
	private Random rng;

	public boolean hasWord(String word) {

		return allWords.contains(word);
	}

	public void addWord(String nom) throws IllegalArgumentException {

		if (nom == null)
			throw new IllegalArgumentException(
					"Can't add a null string to the word store");

		for (int i = 0; i < nom.length(); i++)
			if (nom.charAt(i) < 'a' || nom.charAt(i) > 'z')
				throw new IllegalArgumentException(
						"Can't add a string with characters outside range a..z");

		if (hasWord(nom))
			return;

		allWords.addElement(nom);

	}

	public int numberOfWords() {

		return allWords.size();
	}

	public String toString() {

		return allWords.toString();
	}

	public String randomWord() throws IllegalStateException {

		int size = allWords.size();
		if (size == 0)
			throw new IllegalStateException(
					"Can't get a word from an empty word store");
		return allWords.elementAt(rng.nextInt(size));
	}

	private WordStore words;

	public HangMan1(String word) throws IllegalArgumentException {

		String[] oneword = { word };

		if (word == null)
			throw new IllegalArgumentException(
					"Cannot make a hangman game with no words");
		words = new WordStore(new Random(), oneword);
		randomWord();
	}

	public HangMan1(String[] strings) throws IllegalArgumentException {

		if (strings == null)
			throw new IllegalArgumentException(
					"Cannot make a hangman game with no words");
		words = new WordStore(new Random(), strings);
		randomWord();
	}

	public HangMan1(Random rng, String[] strings)
			throws IllegalArgumentException {

		if (strings == null)
			throw new IllegalArgumentException(
					"Cannot make a hangman game with no words");
		// words = new WordStore(rng, strings);
		if (strings == null)
			throw new IllegalArgumentException(
					"Cannot make a wordstore with no words");
		allWords = new Vector<String>();

		for (int i = 0; i < strings.length; i++) {
			String nom = strings[i];
			if (nom == null)
				throw new IllegalArgumentException(
						"Can't add a null string to the word store");

			for (int ii = 0; ii < nom.length(); ii++)
				if (nom.charAt(ii) < 'a' || nom.charAt(ii) > 'z')
					throw new IllegalArgumentException(
							"Can't add a string with characters outside range a..z");

			// @TODO remove this method
			if (hasWord(nom))
				return;

			allWords.addElement(nom);
			// addWord(strings[i]);
		}

		if (rng == null)
			rng = new Random();
		else
			this.rng = rng;

		// randomWord();
		int size = allWords.size();
		if (size == 0)
			throw new IllegalStateException(
					"Can't get a word from an empty word store");
		currentWord = allWords.elementAt(rng.nextInt(size));
		
		/////////////////////////////
		errorCount = 0;
		won = false;
		lost = false;

		lettersFound = new boolean[currentWord.length()];
		for (int i = 0; i < currentWord.length(); i++) {
			lettersFound[i] = false;
		}

		for (int i = 0; i < ALPHABET_SIZE; i++) {
			lettersTried[i] = false;
		}		
		
	}

	public String getCurrentWord() {
		return currentWord;
	}

	public boolean foundWord() {

		for (int i = 0; i < currentWord.length(); i++)
			if (!lettersFound[i])
				return false;
		return true;
	}

	public int triesLeft() {
		return ERROR_MAX - errorCount;
	}

	public boolean gameOver() {
		return foundWord() || triesLeft() <= 0;
	}

	public String lettersTried() {
		String str = "";
		for (int i = 0; i < ALPHABET_SIZE; i++)

			if (lettersTried[i])
				str = str + ((char) ((int) ('a') + i));
			else
				str = str + "-";

		return str;
	}

	public String lettersInWord() {

		String str = "";

		for (int i = 0; i < currentWord.length(); i++) {
			if (lettersFound[i])
				str = str + currentWord.charAt(i);
			else
				str = str + '?';
		}
		return str;

	}

	public void tryLetter(char letter) throws IllegalStateException,
			IllegalArgumentException {

		if (won)
			throw new IllegalStateException(
					"Game is over: you already found the word");
		if (lost)
			throw new IllegalStateException(
					"Game is over: no more attempts left");
		if (letter < ALPHABET_FROM || letter > ALPHABET_TO)
			throw new IllegalArgumentException("Letters must be in alphabet");
		boolean found = false;
		int index = letter - (int) (ALPHABET_FROM);

		if (lettersTried[index])
			return;

		else {
			lettersTried[index] = true;
			for (int i = 0; i < currentWord.length(); i++)
				if (currentWord.charAt(i) == letter) {
					lettersFound[i] = true;
					found = true;
				}
			if (!found) {
				errorCount++;
				if (errorCount > ERROR_MAX)
					lost = true;
			}
		}
		won = foundWord();
		lost = (triesLeft() < 1);
	}
}
